/*
 * Funny Language - a free style programming language.
 * Copyright (C) 2015 by fanguangping (fanguangping@163.com)
 * operator.c
 */

#include "memory.h"
#include "operator.h"
#include "../../log/logfile.h"

#define BLOCK_SIZE 256


// call/cc
// http://pathtovoid.net/post/2011/12/18/callcc-in-scheme/

Cell* eval(Scheme *sc, String statement) {
	sc->op = cell_op_toplevel;
	sc->input = statement;
	sc->inputPointer = 0;
	Cell* operator = NULL;
	Cell* result = NULL;
	OperatorFunc func = NULL;

	while (TRUE) {
		operator = sc->op;
		//log_cell(sc, operator);
		func = operator->_op;
		result = func(sc);
		//log_cell(sc, result);
		if (type_of(sc, result, PRIMITIVE_EXCEPTION)) {
			// exception handle
			sc->args = &g_nil;
			sc->args = cons(sc, second(result), sc->args);
			sc->args = cons(sc, first(result), sc->args);
			func = third(result)->_op;
			result = func(sc);
		}
		if (type_of(sc, result, EXCEPTION_TYPE)) {
			// exception handle
			// func = find_property_of_object(sc, result, "handler")->_op;
			// result = func(sc);
		}
		if (result == &g_nil)
			return sc->returnValue;
	}
}

/*
static int is_internal_operator(char *name) {
	if (name == NULL || *name == '$')
		return TRUE;
	return FALSE;
}
*/

/*
static void iterator(void *key, void *value, void *user_data) {
	char *name = (char *)key;
	OperatorFunc func = (OperatorFunc)value;
	Scheme *sc = (Scheme *)user_data;

	if (!is_internal_operator(name))
		new_slot_in_env(sc, make_symbol(sc, name), make_procedure(sc, func));
}
*/

//符号列表初始化
/*
static Cell* oblist_initial_value(Scheme *sc) {
	return make_vector(sc, 461); // probably should be bigger
}
*/

void add_constant(Scheme *sc, const char *name, Cell *value) {
	Cell* sym = make_symbol(sc, name);
	sym->_flag |= REF_IMMUTABLE;
	//new_slot_in_env(sc, sym, value);
	add_slot_by_symbol(sc, sc->globalObjects, sym, value);
}

void add_syntax(Scheme *sc, const char *name, Cell *value) {
	Cell* sym = make_syntax(sc, name);
	sym->_flag |= REF_IMMUTABLE;
	//new_slot_in_env(sc, sym, value);
	add_slot_by_symbol(sc, sc->globalObjects, sym, value);
}

void add_operator(Scheme *sc, const char *name, OperatorFunc func) {
	Cell* cell = make_procedure(sc, func);
	add_constant(sc, name, cell);
}

void init_global_symbols(Scheme *sc) {
	;
}
void init_global_syntaxes(Scheme *sc) {
	init_read_operators(sc);
	init_write_operators(sc);
	init_control_operators(sc);
	init_define_operators(sc);
	init_eval_operators(sc);
	init_let_operators(sc);
	init_logic_operators(sc);
}
void init_global_operators(Scheme *sc) {
	init_atom_operators(sc);
	init_boolean_operators(sc);
	init_character_operators(sc);
	init_complex_operators(sc);
	init_decimal_operators(sc);
	init_fraction_operators(sc);
	init_integer_operators(sc);
	init_number_operators(sc);
	init_real_operators(sc);
	init_symbol_operators(sc);
	init_string_operators(sc);

	//init_syntaxes(sc);

	init_class_operators(sc);
	init_closure_operators(sc);
	init_continuation_operators(sc);
	init_environment_operators(sc);
	init_exception_operators(sc);
	init_list_operators(sc);

	//init_object_operators(sc);
	init_pair_operators(sc);
	init_procedure_operators(sc);
	init_promise_operators(sc);
	init_vector_operators(sc);
}
void init_global_constants(Scheme *sc) {
	add_constant(sc, CONSTANT_NAME_NIL, &g_nil);
	init_boolean_constants(sc);
	//init_double_constants(sc);
	//init_symbol_constants(sc);
	init_exception_constants(sc);
}

int scheme_init(Scheme *sc) {
	init_constants();
	init_class_hierarchy(sc);

	sc->lastCellSeg = -1;
	sc->freeCell = &g_nil;
	sc->freeCellCount = 0;
	alloc_cellseg(sc, 3);

	sc->code = &g_nil;
	sc->callStack = &g_nil;
	sc->globalObjects = make_vector(sc, 461); /* probably should be bigger */
	/* init global_env */
	new_frame_in_env(sc, &g_nil);
	sc->globalEnv = sc->env;

	init_global_symbols(sc);
	init_global_syntaxes(sc);
	init_global_operators(sc);
	init_global_constants(sc);

	//init_system_operators(operators);
	//init_command_operators(operators);

	cell_symbol_lambda = make_symbol(sc, "lambda");
	cell_symbol_quote = make_symbol(sc, "quote");
	cell_symbol_this = make_symbol(sc, "this");
	cell_symbol_feed_to = make_symbol(sc, "=>");

	return TRUE;
}
